package vn.com.baseapplication.network;

import java.util.ArrayList;

import org.apache.http.entity.StringEntity;
import org.json.JSONException;

import vn.com.baseapplication.R;
import vn.com.hoasua.database.smng.LinkMng;
import vn.com.hoasua.database.sobject.LinkPost;
import android.content.Context;
import android.util.Log;

import com.google.gson.JsonSyntaxException;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.JsonHttpResponseHandler;

/**
 * Provide basic functions for make a request POST/GET with callback.
 * */
public class BaseNetwork {
	private static final String CONTENT_TYPE = "application/json";
	private long timeout = 0;

	protected AsyncHttpClient client;
	protected Context context;

	private NetworkHandlerCallback callback;

	class CustomJsonResponseHandler extends JsonHttpResponseHandler {
		int requestId;
		boolean fromCache = false;
		boolean finished = false;

		public CustomJsonResponseHandler(int requestId) {
			this(requestId, false);
		}

		public CustomJsonResponseHandler(int requestId, boolean fromCache) {
			this.requestId = requestId;
			this.fromCache = fromCache;
		}

		@Override
		public void onStart() {
			super.onStart();
			callback.onNetLoading(requestId);
		}

		@Override
		protected Object parseResponse(String responseBody)
				throws JSONException {
			finished = true;
			if (fromCache)
				callback.onNetSuccessCache(requestId, responseBody);
			else
				try {
					callback.onNetSuccess(requestId, responseBody);
				} catch (JsonSyntaxException e) {
					Log.e("JSON ERR", responseBody);
				}
			return super.parseResponse(responseBody);
		}

		public void onFailure(String responseBody, Throwable error) {
			super.onFailure(responseBody, error);
			finished = true;
			callback.onNetFailed(requestId, responseBody);
		}

		@Override
		public void onFinish() {
			super.onFinish();
			if (!finished) {
				callback.onNetTimeOut(requestId, new Throwable("request: " + requestId + " is timeout."));
			}
		}
	}

	public BaseNetwork(Context context) {
		if (!(context instanceof NetworkHandlerCallback)) {
			try {
				throw new IllegalAccessException(context.getClass().getName()
						+ " must be an instance of NetworkHandlerCallback.");
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		} else {
			this.callback = (NetworkHandlerCallback) context;
		}

		this.client = new AsyncHttpClient();
		this.context = context;

		this.timeout = Long.valueOf(context.getString(R.string.time_out));
	}

	public BaseNetwork(Context context, NetworkHandlerCallback callback) {
		this.callback = callback;
		this.client = new AsyncHttpClient();
		this.context = context;

		this.timeout = Long.valueOf(context.getString(R.string.time_out));
	}

	public void setContext(Context context) {
		this.context = context;
		if (context instanceof NetworkHandlerCallback) {
			this.callback = (NetworkHandlerCallback) context;
		}
	}

	public Context getContext() {
		return this.context;
	}

	@Override
	protected void finalize() throws Throwable {
		this.client = null;
		this.context = null;
		super.finalize();
	}

	public void post(int requestId, String url, StringEntity entity) {
		if (this.client != null) {
			this.client.post(this.context, url, entity, CONTENT_TYPE, new CustomJsonResponseHandler(requestId));
		}
	}

	public void get(int requestId, Context context, String url) {
		LinkMng linkMng = new LinkMng(context);
		ArrayList<LinkPost> cache = linkMng.select(LinkMng.link, url);
		if (cache == null || cache.isEmpty()) {
			// do nothing
		} else {
			// return cache data
			long timeStamp = cache.get(0).time;
			if ((System.currentTimeMillis() - timeStamp) <= timeout) {
				String json = cache.get(0).response;
				/* json may be array or object */
				try {
					new CustomJsonResponseHandler(requestId, true).parseResponse(json);
				} catch (JSONException e) {
					e.printStackTrace();
				}
			}
		}
		if (this.client != null) {
			this.client.get(context, url, new CustomJsonResponseHandler(requestId));
		}
	}

	public void setCache(String url, String json) {
		LinkMng linkMng = new LinkMng(context);
		LinkPost link = new LinkPost(-1, new String[LinkPost.NUM_FIELDS]);
		link.link = url;
		link.response = json;
		link.time = System.currentTimeMillis();
		ArrayList<LinkPost> lstLink = linkMng.select(LinkMng.link, url);
		if (lstLink == null || lstLink.isEmpty()) {
			linkMng.insertNewTo(link.getValues());
		} else {
			linkMng.edit(lstLink.get(0)._id, link.getValues());
		}
	}
}
